package com.jintian.smart.kernel.orm.query.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.jintian.smart.kernel.common.util.StringUtil;
import com.jintian.smart.kernel.orm.dto.Condition;
import com.jintian.smart.kernel.orm.query.ConditionOperatorEnum;
import com.jintian.smart.kernel.orm.query.IQueryBuilder;
import com.jintian.smart.kernel.orm.query.Query;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.Function;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;

public class SqlQueryBuilder implements IQueryBuilder<String> {

    @Override
    public String build(Query query) throws JSQLParserException {
        List<String> filters = new ArrayList<>();
        String filter = buildCombineCondition(query.getConditionFormat(), query.getConditions());
        if (filter != null) {
            filters.add(filter);
        }
        if (filters.size() == 1) return filters.get(0);
        else if (filters.size() > 1) return "(" + StringUtil.join(filters, ") and (") + ")";
        else return null;
    }

    private static String buildCombineCondition(String conditionFormat, Condition[] conditions) throws JSQLParserException {
        if (conditions == null || conditions.length == 0) return null;

        if (StringUtil.isNotEmpty(conditionFormat)) {
            conditionFormat = conditionFormat.replace("m", "and");
            conditionFormat = conditionFormat.replace("s", "or");
            String sql = "select * from dual where " + fomatCondtion(conditionFormat);
            Select select = (Select) CCJSqlParserUtil.parse(sql);
            PlainSelect body = (PlainSelect) select.getSelectBody();
            Expression expression = body.getWhere();
            return binaryExpressionToQueryBuilder(expression, conditions);
        } else {
            // 遍历组合查询条件，将相关查询组合起来
            List<String> all = new ArrayList<>();

            for (Condition condition : conditions) {
                if (StringUtil.isEmpty(condition.getOperator())) continue;
                all.add(conditionToQueryBuilder(condition));
            }
            if (all.size() == 1) return all.get(0);
            return "(" + StringUtil.join(all, ") and (") + ")";

        }
    }

    private static final Pattern CONDITION_SYMBOL_REGX = Pattern.compile("(%\\d+)");

    private static String fomatCondtion(String conditionFormat) {
        Matcher m = CONDITION_SYMBOL_REGX.matcher(conditionFormat);
        StringBuffer sb = new StringBuffer();
        int start = 0;
        while (m.find()) {
            sb.append(conditionFormat.substring(start, m.start()));
            sb.append("c(").append(m.group().substring(1)).append(")");
            start = m.end();
        }
        sb.append(conditionFormat.substring(start));
        return sb.toString();
    }

    private static String binaryExpressionToQueryBuilder(Expression expression, Condition[] conditions) throws JSQLParserException {
        if (expression instanceof AndExpression) {
            AndExpression and = (AndExpression) expression;
            return "(" + binaryExpressionToQueryBuilder(and.getLeftExpression(), conditions) + ") and (" + binaryExpressionToQueryBuilder(and.getRightExpression(), conditions) + ")";
        } else if (expression instanceof OrExpression) {
            OrExpression or = (OrExpression) expression;
            return "(" + binaryExpressionToQueryBuilder(or.getLeftExpression(), conditions) + ") or (" + binaryExpressionToQueryBuilder(or.getRightExpression(), conditions) + ")";
        } else if (expression instanceof Function) {
            String v = expression.toString();
            Condition condtion = conditions[Integer.parseInt(v.substring(2, v.length() - 1))];
            return conditionToQueryBuilder(condtion);
        } else if (expression instanceof Parenthesis) {
            return binaryExpressionToQueryBuilder(((Parenthesis) expression).getExpression(), conditions);
        }
        throw new JSQLParserException("不支持的SQL表达式:" + expression);
    }

    private static String conditionToQueryBuilder(Condition condition) {
        ConditionOperatorEnum operator = null;
        try {
            operator = ConditionOperatorEnum.valueOf(condition.getOperator());
        } catch (Exception ex) {
            throw new RuntimeException("错误操作符:" + condition.getOperator());
        }
        return operator.sqlFilter(condition);
    }
}
